/*
 * Copyright (c) Tecplot, Inc.
 *
 * All rights reserved.  Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   - Redistributions of source code must retain the above copyright notice, this list of
 *     conditions and the following disclaimer. 
 *   - Redistributions in binary form must reproduce the above copyright notice, this list
 *     of conditions and the following disclaimer in the documentation and/or other
 *     materials provided with the distribution.
 *   - Neither the name of the Tecplot, Inc., nor the names of its contributors may be
 *     used to endorse or promote products derived from this software without specific
 *     prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef STATUS_H_ /* Only include once */
#define STATUS_H_

/*
 * This is a simple class to manage Tecplot's status line when providing updates during a
 * (potentially) long operation.
 */
#include <algorithm>
#include <string>
#include "TECADDON.h"

#undef min

#ifdef Status
#undef Status
#endif

template <typename InterruptExceptionType>
class Status
{
public:
    /**
     * numWorkUnits can be set to the total number of times you plan to call
     * operator++. If left at the default of 0, no progress bar will be shown
     * (just a message will be displayed on the status line).
     */
    Status(const std::string& message,
           size_t             numWorkUnits = 0);

    ~Status();

    /**
     * Set the status line text.
     */
    void setMessage(const std::string& message) const;

    /**
     * Increment the status line to mark the completion of another
     * work unit.
     */
    Status<InterruptExceptionType>& operator++();

    /**
     * Update the progress bar for a given number of completed work units.
     * The units of this parameter should be the same as the "numWorkUnit"
     * value provided in the constructor.
     */
    void update(size_t numWorkUnitsComplete);

private:
    void update();

private:
    double m_totalWorkUnits;
    double m_currentWorkUnit;
};

/**
 */
template <typename InterruptExceptionType>
Status<InterruptExceptionType>::Status(const std::string& message,
                                       size_t             numWorkUnits):
    m_totalWorkUnits(static_cast<double>(numWorkUnits)),
    m_currentWorkUnit(0)
{
    REQUIRE(!message.empty());
    REQUIRE(TecUtilLockIsOn());

    Boolean_t showProgress = m_totalWorkUnits > 0;

    TecUtilStatusStartPercentDone(message.c_str(),
                                  FALSE, // Show stop button
                                  showProgress);
}

/**
 */
template <typename InterruptExceptionType>
Status<InterruptExceptionType>::~Status()
{
    REQUIRE(TecUtilLockIsOn());

    TecUtilStatusFinishPercentDone();
}

/**
 */
template <typename InterruptExceptionType>
void Status<InterruptExceptionType>::setMessage(const std::string& message) const
{
    REQUIRE(!message.empty());
    REQUIRE(TecUtilLockIsOn());

    TecUtilStatusSetPercentDoneText(message.c_str());
}

/**
 */
template <typename InterruptExceptionType>
Status<InterruptExceptionType>& Status<InterruptExceptionType>::operator++()
{
    m_currentWorkUnit += 1.0;
    update();
    return *this;
}

/**
 */
template <typename InterruptExceptionType>
void Status<InterruptExceptionType>::update(size_t numWorkUnitsComplete)
{
    m_currentWorkUnit = static_cast<double>(numWorkUnitsComplete);
    update();
}

/**
 */
template <typename InterruptExceptionType>
void Status<InterruptExceptionType>::update()
{
    REQUIRE(TecUtilLockIsOn());

    if (m_totalWorkUnits > 0)
    {
        double percentDone = m_currentWorkUnit / m_totalWorkUnits * 100.0;
        percentDone = std::min(percentDone, 100.0);
        TecUtilStatusCheckPercentDone(static_cast<int>(percentDone));
    }
}
#endif
